/*
 * mem_storage.h
 *
 *  Created on: Jan 28, 2011
 *      Author: thienlong
 */

#ifndef MEM_STORAGE_H_
#define MEM_STORAGE_H_
#include <assert.h>
#include <stddef.h>
#include <stdlib.h>
#include <stdbool.h>
#include <pthread.h>
#define MEM_STORAGE_ARRAY_LENGTH 32
#define MEM_STORAGE_ARRAY_MAX_SIZE_SUPPORT 1 << 32
#define MEM_BLOCK_DEFAULT_SIZE 65536
#define MEM_STORAGE_SUPPORT_THREAD_SAFE
#define LENGTH_STORAGE_SIZE sizeof(int)

#define GET_REAL_TABLE(abstract_table, type) ((type)(((char *)abstract_table) + LENGTH_STORAGE_SIZE))

#define GET_ABSTRACT_TABLE(real_table, type) ((type)(((char *)real_table) - LENGTH_STORAGE_SIZE))

#define GET_LENGTH(abstract_table) (*((int *) abstract_table))

#define SET_LENGTH(length, abstract_table) { \
	int *segm_cap = (int *) abstract_table; \
	*segm_cap = length; \
}

#define AL_DbgAssert( expr ) assert(expr)
/* default alignment for dynamic data strucutures, resided in storages. */
#define  AL_STRUCT_ALIGN    ((int)sizeof(double))

extern void* fast_malloc(size_t size);
extern void* fast_calloc(size_t size);
extern void fast_free(void* ptr);

typedef struct mem_block {
	struct mem_block *next;
	size_t size;
} mem_block;

typedef struct {
	mem_block *heap_blocks[MEM_STORAGE_ARRAY_LENGTH];
	mem_block *current;					 /* Current memory block */
	mem_block *top; 			         /* top of the stack. */
	mem_block *bottom;  				 /* First allocated block. */
	size_t block_size;          	     /* Block size.                              */
    size_t free_space;              	 /* Remaining free space in current block.   */
#ifdef MEM_STORAGE_SUPPORT_THREAD_SAFE
    bool thread_safe;
    pthread_mutex_t stack_lock;
    pthread_mutex_t heap_lock;
#endif
} mem_storage;


typedef unsigned char uchar;
typedef signed char schar;
typedef enum {
	HEAP_MEM, STACK_MEM
} mem_type;
/* the alignment of all the allocated buffers */
#define  AL_MALLOC_ALIGN    16
#define MEM_BLOCK_HEADER_SIZE (sizeof(mem_block))
#define MEM_BLOCK_DATA_PTR(block) ((void *)((char*)block + MEM_BLOCK_HEADER_SIZE))
#define MEM_BLOCK_PTR(data_ptr) ((mem_block*)((char*) (data_ptr) - MEM_BLOCK_HEADER_SIZE))
#define MEM_BLOCK_DATA_RESIZE(data_ptr, new_size) { \
	mem_block *block = realloc(MEM_BLOCK_PTR(data_ptr), new_size + MEM_BLOCK_HEADER_SIZE); \
	assert(block); \
	block->size = new_size + MEM_BLOCK_HEADER_SIZE; \
	data_ptr = MEM_BLOCK_DATA_PTR(block); \
}

//extern int ceilbase2(int value);
#ifdef MEM_STORAGE_SUPPORT_THREAD_SAFE
extern mem_storage* mem_storage_new(int size, bool thread_safe);
#else
extern mem_storage* mem_storage_new(int size);
#endif
extern mem_block* mem_storage_get_block(mem_storage *storage, int expect_size);
extern void mem_storage_put_block(mem_storage *storage, mem_block *block);

/* Allocate continuous buffer of the specified size in the storage: */
extern void* mem_storage_alloc(mem_storage *storage, int expect_size, mem_type type);
extern void mem_storage_free(mem_storage **storage);
extern void mem_storage_clear(mem_storage *storage);
extern void mem_free(void *, mem_storage*, mem_type);
#endif /* MEM_STORAGE_H_ */
